<?php
// +----------------------------------------------------------------------
// | INPHP
// +----------------------------------------------------------------------
// | Copyright (c) 2021 https://inphp.cc All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://opensource.org/licenses/MIT )
// +----------------------------------------------------------------------
// | Author: lulanyin <me@lanyin.lu>
// +----------------------------------------------------------------------
//                        连接池
// +----------------------------------------------------------------------
namespace Inphp\DB;

use Swoole\Coroutine\Channel;

/**
 * 连接池
 * Class ConnectionPools
 * @package Inphp\DB
 */
class ConnectionPools
{
    /**
     * 连接池默认数量
     * @var int
     */
    private int $length;

    /**
     * @var Channel
     */
    private Channel $channels;

    /**
     * 请在协程中初始化，否则无法使用
     * 初始化连接池
     * Pool constructor.
     * @param int $size 每个 Worker 最多可使用的连接数据
     */
    public function __construct(int $size = 5)
    {
        $this->length = $size;
        $this->putConnect();
    }

    public function putConnect()
    {
        $this->channels = new Channel($this->length);
        for($i = 0; $i < $this->length; $i ++){
            $this->put($this->connect());
        }
    }

    /**
     * 回收连接
     * @param Connection $connection
     */
    public function put(Connection $connection)
    {
        $this->channels->push($connection);
    }

    /**
     * 获取连接
     * @return false|Connection
     */
    public function get() : Connection|false
    {
        $pdo = $this->channels->pop(2);
        if($pdo == null){
            return false;
        }
        return $pdo;
    }

    /**
     * @return Connection
     */
    private function connect() : Connection
    {
        return new Connection(DB::getConfig());
    }


    /**
     * @var ConnectionPools|null
     */
    public static ConnectionPools|null $pools = null;

    /**
     * 获取连接池
     * @return Connection
     */
    public static function getConnection() : Connection
    {
        if(null == self::$pools){
            self::init();
        }
        return self::$pools->get();
    }

    /**
     * 释放回去
     * @param Connection $connection
     */
    public static function putConnection(Connection $connection)
    {
        if(null !== self::$pools){
            //如果回收的时候，事务还在进行，需要把事务提交了
            if($connection->in_transaction){
                $connection->getPdo('write')->commit();
            }
            self::$pools->put($connection);
        }
    }

    /**
     * 初始化
     */
    public static function init(){
        if(null == self::$pools){
            $config = DB::getConfig();
            $size = $config['pools'] ?? (defined("INPHP_DB_SWOOLE_POOLS") ? INPHP_DB_SWOOLE_POOLS : 5);
            $size = is_numeric($size) && $size>0 ? intval($size) : 5;
            self::$pools = new ConnectionPools($size);
        }
    }
}